package weiyao.xinxidasai.Utils.Encryption;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class KeyIdGenerator {

    private static final String HMAC_ALGORITHM = "HmacSHA256";
    private static final byte[] SECRET_KEY = "xinxidasai".getBytes();

    // 53位掩码 (0x1FFFFFFFFFFFFFL)
    private static final long MASK_53 = (1L << 53) - 1;
    private static final long MASK_A = 0x5A827999L;
    private static final long MASK_B = 0x6ED9EBA1L;
    private static final long SMALL_ID_SALT = 0x9E3779B9L;
    private static final int MIN_SHIFT = 5;

    /**
     * 生成紧凑型密钥ID (53位安全整数)
     * @param userId 用户ID (只使用低32位)
     * @param r 混沌参数R
     * @param x0 混沌初始值X0
     * @param iterations 迭代次数
     * @return 53位密钥ID (long类型)
     */
    public static long generateKeyId(long userId, double r, double x0, long iterations) {
        // 1. 只使用userId的低32位
        long maskedUserId = userId & 0xFFFFFFFFL;

        // 2. 计算HMAC校验码
        byte[] hmac = calculateHmac(userId, r, x0, iterations);

        // 3. 取HMAC中间24位
        long hmacMid24 = ((hmac[2] & 0xFF) << 16) |
                ((hmac[3] & 0xFF) << 8) |
                (hmac[4] & 0xFF);

        // 4. 取高21位作为校验码
        long checksum = hmacMid24 >>> 3;  // 24位右移3位 = 21位

        // 5. 组合用户ID和校验码 (32位 + 21位 = 53位)
        long compactId = (maskedUserId << 21) | checksum;

        // 6. 添加53位混淆层
        return applyObfuscation(compactId, maskedUserId);
    }

    /**
     * 生成密钥ID字符串
     */
    public static String generateKeyIdAsString(long userId, double r, double x0, long iterations) {
        long rawId = generateKeyId(userId, r, x0, iterations);
        return Long.toHexString(rawId);
    }

    /**
     * 验证密钥ID
     */
    public static boolean validateKeyId(long keyId, long userId, double r, double x0, long iterations) {
        try {
            // 1. 只使用userId的低32位
            long maskedUserId = userId & 0xFFFFFFFFL;

            // 2. 移除混淆层
            long deobfuscated = removeObfuscation(keyId, maskedUserId);

            // 3. 提取用户ID和校验码
            long embeddedUserId = deobfuscated >>> 21;
            long embeddedChecksum = deobfuscated & 0x1FFFFF; // 21位掩码

            // 4. 验证用户ID一致性
            if (maskedUserId != embeddedUserId) {
                return false;
            }

            // 5. 重新计算HMAC
            byte[] hmac = calculateHmac(userId, r, x0, iterations);
            long hmacMid24 = ((hmac[2] & 0xFF) << 16) |
                    ((hmac[3] & 0xFF) << 8) |
                    (hmac[4] & 0xFF);
            long newChecksum = hmacMid24 >>> 3;  // 取21位

            // 6. 比较校验码
            return embeddedChecksum == newChecksum;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 验证密钥ID (字符串形式)
     */
    public static boolean validateKeyId(String keyIdString, long userId, double r, double x0, long iterations) {
        try {
            long rawId = Long.parseLong(keyIdString, 16);
            return validateKeyId(rawId, userId, r, x0, iterations);
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 53位混淆层
     */
    private static long applyObfuscation(long value, long userId) {
        value &= MASK_53;  // 确保在53位范围内
        long factor = createObfuscationFactor(userId) & MASK_53;
        int shift = calculateShift(userId) % 53;  // 移位范围0-52

        long stage1 = value ^ factor;
        long stage2 = rotateLeft53(stage1, shift);
        return stage2 ^ MASK_A;
    }

    /**
     * 移除53位混淆层
     */
    private static long removeObfuscation(long value, long userId) {
        value &= MASK_53;  // 确保在53位范围内
        long factor = createObfuscationFactor(userId) & MASK_53;
        int shift = calculateShift(userId) % 53;  // 移位范围0-52

        long stage1 = value ^ MASK_A;
        long stage2 = rotateRight53(stage1, shift);
        return stage2 ^ factor;
    }

    /**
     * 创建混淆因子
     */
    private static long createObfuscationFactor(long userId) {
        long factor = userId ^ SMALL_ID_SALT;
        factor = (factor << 32) | (factor >>> 32);  // 64位交换高低位
        return factor * SMALL_ID_SALT;  // 乘法扩散
    }

    /**
     * 计算移位量
     */
    private static int calculateShift(long userId) {
        int baseShift = (int)(userId & 0x1F);  // 取低5位 (0-31)
        return (baseShift | MIN_SHIFT) & 0x1F; // 确保最小移位5
    }

    /**
     * 53位循环左移
     */
    private static long rotateLeft53(long value, int shift) {
        value &= MASK_53;
        shift %= 53;
        if (shift == 0) return value;

        long high = value << shift;
        long low = value >>> (53 - shift);
        return (high | low) & MASK_53;
    }

    /**
     * 53位循环右移
     */
    private static long rotateRight53(long value, int shift) {
        value &= MASK_53;
        shift %= 53;
        if (shift == 0) return value;

        long low = value >>> shift;
        long high = value << (53 - shift);
        return (high | low) & MASK_53;
    }

    /**
     * 计算HMAC值
     */
    private static byte[] calculateHmac(long userId, double r, double x0, long iterations) {
        try {
            Mac hmac = Mac.getInstance(HMAC_ALGORITHM);
            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY, HMAC_ALGORITHM);
            hmac.init(keySpec);

            ByteBuffer buffer = ByteBuffer.allocate(32)
                    .order(ByteOrder.BIG_ENDIAN)
                    .putLong(userId)
                    .putDouble(r)
                    .putDouble(x0)
                    .putLong(iterations);

            return hmac.doFinal(buffer.array());
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("HMAC calculation failed", e);
        }
    }
}